Home | History | Annotate | Download | only in llvm
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "intrinsic_helper.h"
     18 
     19 #include "ir_builder.h"
     20 
     21 #include <llvm/IR/Attributes.h>
     22 #include <llvm/IR/DerivedTypes.h>
     23 #include <llvm/IR/Function.h>
     24 #include <llvm/IR/IRBuilder.h>
     25 #include <llvm/IR/Intrinsics.h>
     26 
     27 namespace art {
     28 namespace llvm {
     29 
     30 const IntrinsicHelper::IntrinsicInfo IntrinsicHelper::Info[] = {
     31 #define DEF_INTRINSICS_FUNC(_, NAME, ATTR, RET_TYPE, ARG1_TYPE, ARG2_TYPE, \
     32                                                      ARG3_TYPE, ARG4_TYPE, \
     33                                                      ARG5_TYPE) \
     34   { #NAME, ATTR, RET_TYPE, { ARG1_TYPE, ARG2_TYPE, \
     35                              ARG3_TYPE, ARG4_TYPE, \
     36                              ARG5_TYPE} },
     37 #include "intrinsic_func_list.def"
     38 };
     39 
     40 static ::llvm::Type* GetLLVMTypeOfIntrinsicValType(IRBuilder& irb,
     41                                                    IntrinsicHelper::IntrinsicValType type) {
     42   switch (type) {
     43     case IntrinsicHelper::kVoidTy: {
     44       return irb.getVoidTy();
     45     }
     46     case IntrinsicHelper::kJavaObjectTy: {
     47       return irb.getJObjectTy();
     48     }
     49     case IntrinsicHelper::kJavaMethodTy: {
     50       return irb.getJMethodTy();
     51     }
     52     case IntrinsicHelper::kJavaThreadTy: {
     53       return irb.getJThreadTy();
     54     }
     55     case IntrinsicHelper::kInt1Ty:
     56     case IntrinsicHelper::kInt1ConstantTy: {
     57       return irb.getInt1Ty();
     58     }
     59     case IntrinsicHelper::kInt8Ty:
     60     case IntrinsicHelper::kInt8ConstantTy: {
     61       return irb.getInt8Ty();
     62     }
     63     case IntrinsicHelper::kInt16Ty:
     64     case IntrinsicHelper::kInt16ConstantTy: {
     65       return irb.getInt16Ty();
     66     }
     67     case IntrinsicHelper::kInt32Ty:
     68     case IntrinsicHelper::kInt32ConstantTy: {
     69       return irb.getInt32Ty();
     70     }
     71     case IntrinsicHelper::kInt64Ty:
     72     case IntrinsicHelper::kInt64ConstantTy: {
     73       return irb.getInt64Ty();
     74     }
     75     case IntrinsicHelper::kFloatTy:
     76     case IntrinsicHelper::kFloatConstantTy: {
     77       return irb.getFloatTy();
     78     }
     79     case IntrinsicHelper::kDoubleTy:
     80     case IntrinsicHelper::kDoubleConstantTy: {
     81       return irb.getDoubleTy();
     82     }
     83     case IntrinsicHelper::kNone:
     84     case IntrinsicHelper::kVarArgTy:
     85     default: {
     86       LOG(FATAL) << "Invalid intrinsic type " << type << "to get LLVM type!";
     87       return NULL;
     88     }
     89   }
     90   // unreachable
     91 }
     92 
     93 IntrinsicHelper::IntrinsicHelper(::llvm::LLVMContext& context,
     94                                  ::llvm::Module& module) {
     95   IRBuilder irb(context, module, *this);
     96 
     97   ::memset(intrinsic_funcs_, 0, sizeof(intrinsic_funcs_));
     98 
     99   // This loop does the following things:
    100   // 1. Introduce the intrinsic function into the module
    101   // 2. Add "nocapture" and "noalias" attribute to the arguments in all
    102   //    intrinsics functions.
    103   // 3. Initialize intrinsic_funcs_map_.
    104   for (unsigned i = 0; i < MaxIntrinsicId; i++) {
    105     IntrinsicId id = static_cast<IntrinsicId>(i);
    106     const IntrinsicInfo& info = Info[i];
    107 
    108     // Parse and construct the argument type from IntrinsicInfo
    109     ::llvm::Type* arg_type[kIntrinsicMaxArgc];
    110     unsigned num_args = 0;
    111     bool is_var_arg = false;
    112     for (unsigned arg_iter = 0; arg_iter < kIntrinsicMaxArgc; arg_iter++) {
    113       IntrinsicValType type = info.arg_type_[arg_iter];
    114 
    115       if (type == kNone) {
    116         break;
    117       } else if (type == kVarArgTy) {
    118         // Variable argument type must be the last argument
    119         is_var_arg = true;
    120         break;
    121       }
    122 
    123       arg_type[num_args++] = GetLLVMTypeOfIntrinsicValType(irb, type);
    124     }
    125 
    126     // Construct the function type
    127     ::llvm::Type* ret_type =
    128         GetLLVMTypeOfIntrinsicValType(irb, info.ret_val_type_);
    129 
    130     ::llvm::FunctionType* type =
    131         ::llvm::FunctionType::get(ret_type,
    132                                   ::llvm::ArrayRef< ::llvm::Type*>(arg_type, num_args),
    133                                   is_var_arg);
    134 
    135     // Declare the function
    136     ::llvm::Function *fn = ::llvm::Function::Create(type,
    137                                                     ::llvm::Function::ExternalLinkage,
    138                                                      info.name_, &module);
    139 
    140     if (info.attr_ & kAttrReadOnly) {
    141         fn->setOnlyReadsMemory();
    142     }
    143     if (info.attr_ & kAttrReadNone) {
    144         fn->setDoesNotAccessMemory();
    145     }
    146     // None of the intrinsics throws exception
    147     fn->setDoesNotThrow();
    148 
    149     intrinsic_funcs_[id] = fn;
    150 
    151     DCHECK_NE(fn, static_cast< ::llvm::Function*>(NULL)) << "Intrinsic `"
    152         << GetName(id) << "' was not defined!";
    153 
    154     // Add "noalias" and "nocapture" attribute to all arguments of pointer type
    155     for (::llvm::Function::arg_iterator arg_iter = fn->arg_begin(),
    156             arg_end = fn->arg_end(); arg_iter != arg_end; arg_iter++) {
    157       if (arg_iter->getType()->isPointerTy()) {
    158         std::vector< ::llvm::Attribute::AttrKind> attributes;
    159         attributes.push_back(::llvm::Attribute::NoCapture);
    160         attributes.push_back(::llvm::Attribute::NoAlias);
    161         ::llvm::AttributeSet attribute_set = ::llvm::AttributeSet::get(fn->getContext(),
    162                                                                        arg_iter->getArgNo(),
    163                                                                        attributes);
    164         arg_iter->addAttr(attribute_set);
    165       }
    166     }
    167 
    168     // Insert the newly created intrinsic to intrinsic_funcs_map_
    169     if (!intrinsic_funcs_map_.insert(std::make_pair(fn, id)).second) {
    170       LOG(FATAL) << "Duplicate entry in intrinsic functions map?";
    171     }
    172   }
    173 
    174   return;
    175 }
    176 
    177 }  // namespace llvm
    178 }  // namespace art
    179