• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GetLLVMTypeOfIntrinsicValType(IRBuilder & irb,IntrinsicHelper::IntrinsicValType type)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 
IntrinsicHelper(::llvm::LLVMContext & context,::llvm::Module & module)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